#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/blkdev.h>
#include <linux/fs.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/kernfs.h>

MODULE_AUTHOR("Arkis");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("test-page");

static const char *g_devpath = "/sys/block/nvme0n1";

static int __init test_init(void)
{
    int error;
    struct path path;
    struct path path2;
    struct kobject *kobj = NULL;
    struct kernfs_node *node = NULL;
    struct device *dev = NULL;
    struct block_device *bdev = NULL;
    struct gendisk *disk = NULL;
    unsigned int flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
    struct file_system_type *fs_type = NULL;

    printk("test_start\n");
    fs_type = get_fs_type("sysfs");
    if (fs_type == NULL) {
        printk(KERN_ERR "Can't get sysfs file system type\n");
        return 0;
    }
    module_put(fs_type->owner);

    error = kern_path(g_devpath, flags, &path);
    if (error) {
        printk(KERN_ERR "Can't get sysfs path\n");
        return 0;
    }
    path_put(&path);

    error = kern_path("/sys", flags, &path2);
    if (error) {
        printk(KERN_ERR "Can't get sysfs path\n");
        return 0;
    }
    printk("sysfs path: %p\n", path.mnt->mnt_sb->s_op);
    printk("sysfs path: %p\n", path2.mnt->mnt_sb->s_op);
    path_put(&path2);

    if (path.mnt == NULL || path.mnt->mnt_sb == NULL) {
        printk(KERN_ERR "Can't get sysfs dentry\n");
        return 0;
    }
    if (path.mnt->mnt_sb->s_type != fs_type) {
        printk(KERN_ERR "Can't get sysfs dentry\n");
        return 0;
    }
	if (d_really_is_negative(path.dentry)) {
		return 0;
    }
    node = (struct kernfs_node *)d_inode(path.dentry)->i_private;
    path_put(&path);
    if (node == NULL) {
        printk(KERN_ERR "Can't get sysfs node\n");
        return 0;
    }

    kobj = (struct kobject *)node->priv;
    if (kobj == NULL) {
        printk(KERN_ERR "Can't get sysfs kobject\n");
        return 0;
    }
    dev = container_of(kobj, struct device, kobj);
    if (dev == NULL) {
        printk(KERN_ERR "Can't get sysfs device\n");
        return 0;
    }
    bdev = container_of(dev, struct block_device, bd_device);
    if (bdev == NULL) {
        printk(KERN_ERR "Can't get sysfs block device\n");
        return 0;
    }
    disk = bdev->bd_disk;
    if (disk == NULL) {
        printk(KERN_ERR "Can't get sysfs gendisk\n");
        return 0;
    }
    printk("disk name: %s\n", disk->disk_name);
    printk("test_done\n");
    return 0;
}

static void __exit test_exit(void)
{
    printk("test_exit\n");
}

module_init(test_init)
module_exit(test_exit)
